﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Wicresoft.EKA.CommonExtensions;

namespace Wicresoft.EKA.NRemedy
{
    public class ARLoginContextPool : ICleanUp
    {

        private static ARLoginContextPool _instance;

        private static readonly Object lockObject = new Object();

        private Dictionary<string, ARLoginContextAndLastUsedTime> items;

        private ARLoginContextPool()
        {
            items = new Dictionary<string, ARLoginContextAndLastUsedTime>();
            CleanUpThread cleanThread = new CleanUpThread(this, this._sleepTime);
            Thread t = new Thread(new ThreadStart(cleanThread.run));
            t.Start();
        }

        public static ARLoginContextPool Instance
        {
            get
            {
                lock (lockObject)
                {
                    if (_instance == null)
                    {
                        _instance = new ARLoginContextPool();
                    }
                    return _instance;
                }
            }
        }

        public void Add(string name, ARLoginContext context)
        {
            lock (items)
            {
                int count = items.Keys.Count;
                if (count < this._poolSize || 0 == _poolSize)
                {
                    items.Add(name, new ARLoginContextAndLastUsedTime() { LogInContext = context, LastUsedTime = DateTime.Now });
                }
                else
                {
                    DateTime min;
                    string keyMin = string.Empty;

                    while (count >= this._poolSize)
                    {
                        min = items.Select(o => o.Value.LastUsedTime).Min();
                        keyMin = items.First(p => p.Value.LastUsedTime == min).Key;

                        items[keyMin].Dispose();

                        items.Remove(keyMin);
                        count = items.Keys.Count;
                    }

                }
            }

        }


        public IARServer CreateARServer()
        {
            return new ARServer();
        }

        public ARLoginContext GetLoginContext(string key)
        {
            lock (items)
            {
                if (items.ContainsKey(key))
                {
                    ARLoginContextAndLastUsedTime item = items[key];
                    item.LastUsedTime = DateTime.Now;
                    return item.LogInContext;
                }
                else
                {
                    throw new InvalidOperationException("The ARLoginContext pool don't have the Key: " + key);
                }

            }
        }

        public bool ContainsKey(string key)
        {
            return items.ContainsKey(key);
        }

        private int _expirationTime = 2 * 60 * 60 * 1000;

        public int ExpirationTime
        {
            get
            {
                return this._expirationTime;
            }
            set
            {
                this._expirationTime = value;
            }
        }

        private int _sleepTime = 5 * 60 * 1000;

        public int SleepTime
        {
            get
            {
                return this._sleepTime;
            }
            set
            {
                this._sleepTime = value;
            }
        }

        private int _poolSize = 0;

        public int PoolSize
        {
            get
            {
                return this._poolSize;
            }
            set
            {
                this._poolSize = value;
            }
        }

        public void Clean()
        {
            lock (items)
            {
                var expires = items.Where(i => i.Value.LastUsedTime.AddMilliseconds(_expirationTime) <= DateTime.Now).ToList();
                foreach (var item in expires)
                {
                    ARLoginContextAndLastUsedTime asa = item.Value;
                    asa.Dispose();
                    items.Remove(item.Key);
                }
            }
        }


    }
}
